<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>原型链</title>
</head>
<body>
<!-- 
一、原型
    构造函数都有prototype属性，名为显示原型属性，在定义函数时添加的，默认是一个空的Object对象（没有自己添加的属性）
    实例对象都有__proto__属性，名为隐式原型属性，在创建实例时添加的，指向构造函数的prototype属性
    实例对象的__proto__的值等于构造函数的prototype的值

二、原型链
    * 访问一个对象的属性时，
        * 现在自身上查找，找到返回，
        * 如果没有，再沿着__proto__这条链向上查找，找到返回，
        * 如果最终没有找到，返回undefined。
    * 别名：隐式原型链
    * 作用：查找对象的属性（方法）
三、构造函数、原型、实例对象的关系（图解，2张图，在images文件里）

-->
</body>
<script type="text/javascript">
    // 创建构造函数
    function Fn(){

    }
    // 给原型对象添加方法
    Fn.prototype.test = function(){
        console.log('test')
    }
    // 创建实例对象
    var fn = new Fn()
    // 实例对象查找属性
    fn.test()

    // 实例对象的隐式原型属性等于构造函数的显示原型属性 ！！（很重要，要刻在骨子里）
    console.log(fn.__proto__ === Fn.prototype)

    
    // 函数的显式原型对象默认是一个空的Object实例对象（但Object不满足）
    console.log(Object.prototype instanceof Object) // false 因为Object.prototype.__proto__ = null


    // Fn的prototype默认是一个Object空对象，实际是被Object创建出来的，Fn.prototype = new Object()
    // 所以Fn.prototype也是一个实例对象，也有__proto__，指向Object构造函数的prototype
    console.log(Fn.prototype.__proto__ === Object.prototype)
    // 同理，Object.prototype也是Object创建，是一个实例对象，也有__proto__，值为null，也是原型链的尽头
    console.log(Object.prototype.__proto__ === null)


    // 所有函数都是Function的实例，包括它自身，函数创建实际是这样：let Fn = new Function()
    // 所以Fn函数，也是Function的实例对象，也有__proto__，指向Function构造函数的prototype
    console.log(Fn.__proto__ === Function.prototype)
    // Object构造函数同理也是被Function创建的，所以也是实例对象，也有__proto__，指向Function构造函数的prototype
    console.log(Object.__proto__ === Function.prototype)
    // Function函数是自己new自己，它也有__proto__，指向它自己的prototype
    console.log(Function.__proto__ === Function.prototype)





    // 原型面试题
    // 测试题1
    // function A(){}
    // A.prototype.n = 1
    // var b = new A()
    // A.prototype = {
    //     n: 2,
    //     m: 3
    // }
    // var c = new A()
    // console.log(b.n, b.m, c.n, c.m) // 1, undefined, 2, 3

    // 测试题2
    function F(){}
    Object.prototype.a = function(){
        console.log('a()')
    }
    Function.prototype.b = function(){
        console.log('b()')
    }
    var f = new F()
    f.a()
    f.b()
    F.a()
    F.b()




    /*
        instanceof关键字：判断对象的具体类型
        例如 a instanceof b, 查看 b.prototype 是否在 a 的隐式原型链上
    */

    var d = []
    var e = {}
    console.log(d instanceof Object)
    console.log(Array instanceof Object)
    console.log(Function instanceof Object)

    function A(){}
    let a = new A()
    Object.prototype.b = function(){}
    Function.prototype.c = function(){}
    console.log(a.b, a.c)
    console.log(a instanceof Object)
    console.log(a instanceof Function)
    console.log(A instanceof Function) 
    console.log(Function instanceof Function) 
    console.log(Function instanceof Object)
    console.log(A instanceof Object)


</script>
</html>